//    LunchIT - Tool to make decisions of a lunch restaurant.
//    Copyright (C) 2010 Jukka Hell
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

package fi.hell.lunchit

import fi.hell.util.CookieService

class User {
	
    static hasMany = [rounds:Round]
    static belongsTo = ["company":Company]

    String firstName
    String lastName
    String email
    String password

    static constraints = {
        firstName	(blank:false)
        lastName	(blank:false)
        email		(blank:false, email:true)
        password	(blank:false)
    }
	
    String toString() {
        return firstName + " " + lastName[0] + "."
    }
	
    /**
     * Returns users favourit restaurant. Selects most selected restaurant.
     */
    Map<Restaurant, Integer> favouritRestaurants(int max = 20) {
		
        List results = Round.createCriteria().list {
            eq('user', this)
            projections {
                groupProperty("selection")
                count("selection", "selectionCount")
            }
            order("selectionCount", "desc")
            maxResults(max)
        }

        Map<Restaurant, Integer> topSelections = [:]
        for(int i = 0; i < results.size(); i++) {
            if (results[i][1] > 0) {
                topSelections[results[i][0]] = results[i][1] as int
            }
        }

        return topSelections
    }

    int moneyUsed() {
        int sum = Round.createCriteria().get {
            eq('user', this)
            projections {
                sum("price")
            }
        }

        return sum ?: 0
    }
	
    static Map<User, Integer> totalExpenditures(int max = 5, String orderDirection = "desc") {
        List results = Round.createCriteria().list {
            projections {
                groupProperty("user")
                sum("price", "priceSum")
            }
            order("priceSum", orderDirection)
            maxResults(max)
        }

        Map<User, Integer> prodigalUsers = [:]
        for(int i = 0; i < results.size(); i++) {
            if (results[i][1] > 0) {
                prodigalUsers[results[i][0]] = results[i][1] as int
            }
        }

        return prodigalUsers
    }

    static Map<User, Integer> averageExpenditures(int max = 5, String orderDirection = "desc") {
        List results = Round.createCriteria().list {
            projections {
                groupProperty("user")
                avg("price", "priceAvg")
            }
            order("priceAvg", orderDirection)
            maxResults(max)
        }

        Map<User, Integer> avgExpenditures = [:]
        for(int i = 0; i < results.size(); i++) {
            if (results[i][1] > 0) {
                avgExpenditures[results[i][0]] = results[i][1] as int
            }
        }

        return avgExpenditures
    }
	
    Map<Restaurant, Integer> mostVotedRestaurants(int max = 20) {
        List results = Vote.createCriteria().list {
            round {
                eq('user', this)
            }
            projections {
                groupProperty("restaurant")
                sum("vote", "voteSum")
            }
            order("voteSum", "desc")
            maxResults(max)
        }

        Map<Restaurant, Integer> topVotes = [:]
        for(int i = 0; i < results.size(); i++) {
            if (results[i][1] > 0) {
                topVotes[results[i][0]] = results[i][1] as int
            }
        }

        return topVotes
    }
	
	static User getLoggedInUser() {
		String email = CookieService.getCookie('loginCookie');
        if (email) {
            return User.findByEmail(email);
        } else {
            null;
        }
	}

	
    static Map<User, Integer> mostSelectionsByTagName(String tag, int max = 1) {
        List results = User.createCriteria().list {
            rounds {
                selection {
                    tags {
                        eq("name", tag)
                    }
                }
            }
            projections {
                rounds {
                    groupProperty("user")
                }
                count("id", "selectionCount")
            }
            order("selectionCount", "desc")
            maxResults(max)
        }
		
        Map<User, Integer> taggers = [:]
        for(int i = 0; i < results.size(); i++) {
            if (results[i][1] > 0) {
                taggers[results[i][0]] = results[i][1] as int
            }
        }

        return taggers
    }

    static Map<User, Integer> mostVersatileUsers(int max = 5) {
        List mostVersatileUsers = Round.createCriteria().list {
            projections {
                groupProperty("user")
                countDistinct("selection", "selectionCount")
            }
            maxResults(max)
            order("selectionCount", "desc")
        }

        Map<User, Integer> results = [:]
        for (Map item in mostVersatileUsers) {
            results[item[0]] = item[1]
        }

        return results
    }

    static Map<User, Integer> luncheonVoucherUsers(int max = 5, String orderDirection = "desc") {
        List luncheonVoucherUsers = Round.createCriteria().list {
            eq("luncheonVoucherUsed", true)
            projections {
                groupProperty("user")
                count("id", "voucherCount")
            }
            maxResults(max)
            order("voucherCount", orderDirection)
        }

        Map<User, Integer> results = [:]
        for (Map item in luncheonVoucherUsers) {
            results[item[0]] = item[1]
        }

        return results
    }

    int luncheonVoucherSavings() {
        if (this.company?.luncheonVoucherProfitValue > 0) {
            int originalExpenditures = Round.createCriteria().get {
                eq('user', this)
                eq('luncheonVoucherUsed', true)
                projections {
                    sum('originalPrice')
                }
            }

            int userExpenditures = Round.createCriteria().get {
                eq('user', this)
                eq('luncheonVoucherUsed', true)
                projections {
                    sum('price')
                }
            }

            if (originalExpenditures && userExpenditures) {
                return originalExpenditures - userExpenditures
            } else {
                return 0
            }
        }
        return 0
    }
}
